﻿using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Channels;
using Microsoft.ResourceManagement.Client.WsEnumeration;
using System.Text;

namespace Microsoft.ResourceManagement.Client.WsEnumeration
{
    /// <summary>
    /// Given an Xpath filter, the enumeration endpoint returns a collection of resources that match the filter.
    /// </summary>
    public class WsEnumerationClient : System.ServiceModel.ClientBase<IEnumerate>, IEnumerate
    {
        public WsEnumerationClient()
            : base()
        {
        }

        public WsEnumerationClient(string endpointConfigurationName) :
            base(endpointConfigurationName)
        {
        }

        public WsEnumerationClient(string endpointConfigurationName, string remoteAddress) :
            base(endpointConfigurationName, remoteAddress)
        {
        }

        public WsEnumerationClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
            base(endpointConfigurationName, remoteAddress)
        {
        }

        public WsEnumerationClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
            base(binding, remoteAddress)
        {
        }

        public Message Enumerate(Message request)
        {
            IEnumerate channel = base.ChannelFactory.CreateChannel();
            try
            {
                Message ret = channel.Enumerate(request);
                ((IDisposable)channel).Dispose();
                return ret;
            }
            catch (Exception)
            {
                if (((ICommunicationObject)channel).State == CommunicationState.Faulted)
                {
                    ((ICommunicationObject)channel).Abort();
                }
                throw;
            }
        }

        public EnumerateResponse Enumerate(EnumerationRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            Message enumerateRequest = null;
            lock (request)
            {
                enumerateRequest = Message.CreateMessage(MessageVersion.Default, Constants.WsEnumeration.EnumerateAction, request, new ClientSerializer(typeof(EnumerationRequest)));
            }
            Message enumerateResponse = Enumerate(enumerateRequest);
            if (enumerateResponse.IsFault)
            {
                // handle fault will throw a .NET exception
                ClientHelper.HandleFault(enumerateResponse);
            }

            EnumerateResponse enumerateResponseTyped = enumerateResponse.GetBody<EnumerateResponse>(new ClientSerializer(typeof(EnumerateResponse)));
            return enumerateResponseTyped;
        }

        public Message Pull(Message request)
        {
            IEnumerate channel = base.ChannelFactory.CreateChannel();
            try
            {
                Message ret = channel.Pull(request);
                ((IDisposable)channel).Dispose();
                return ret;
            }
            catch (Exception)
            {
                if (((ICommunicationObject)channel).State == CommunicationState.Faulted)
                {
                    ((ICommunicationObject)channel).Abort();
                }
                throw;
            }
        }

        public PullResponse Pull(PullRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }
            if(request.EnumerationContext == null)
            {
                throw new InvalidOperationException("EnumerationContext must be set in order to call Pull");
            }
            Message pullRequest;
            lock (request)
            {
                 pullRequest = Message.CreateMessage(MessageVersion.Soap12WSAddressing10, Constants.WsEnumeration.PullAction, request, new ClientSerializer(typeof(PullRequest)));
            }
            Message pullResponse = Pull(pullRequest);
            if(pullResponse.IsFault)
            {
                // handle fault will throw a .NET exception
                ClientHelper.HandleFault(pullResponse);
            }

            PullResponse pullResponseTyped = pullResponse.GetBody<PullResponse>(new ClientSerializer(typeof(PullResponse)));
            return pullResponseTyped;
        }
    }
}
